﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FlashWindow.cs" company="Elilink">
//   Defor
// </copyright>
// <summary>
//   The flash window.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Deployment.Tools
{
    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    /// <summary>
    /// The flash window.
    /// </summary>
    public static class FlashWindow
    {
        #region Constants

        /// <summary>
        ///     Flash both the window caption and taskbar button.
        ///     This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
        /// </summary>
        public const uint FlashAll = 3;

        /// <summary>
        ///     Flash the window caption.
        /// </summary>
        public const uint FlashCaption = 1;

        /// <summary>
        ///     Stop flashing. The system restores the window to its original state.
        /// </summary>
        public const uint FlashStop = 0;

        /// <summary>
        ///     Flash continuously, until the FLASHW_STOP flag is set.
        /// </summary>
        public const uint FlashTimer = 4;

        /// <summary>
        ///     Flash continuously until the window comes to the foreground.
        /// </summary>
        public const uint FlashTimerNoForeground = 12;

        /// <summary>
        ///     Flash the taskbar button.
        /// </summary>
        public const uint FlashTray = 2;

        #endregion

        #region Properties

        /// <summary>
        ///     Gets a value indicating whether the application is running on Windows 2000 or later.
        /// </summary>
        private static bool Win2000OrLater
        {
            get
            {
                return Environment.OSVersion.Version.Major >= 5;
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Flash the specified Window (Form) until it receives focus.
        /// </summary>
        /// <param name="form">
        /// The Form (Window) to Flash.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool Flash(Form form)
        {
            // Make sure we're running under Windows 2000 or later
            if (Win2000OrLater)
            {
                FlashInfo fi = Create_FlashInfo(form.Handle, FlashAll | FlashTimerNoForeground, uint.MaxValue, 0);
                return FlashWindowEx(ref fi);
            }

            return false;
        }

        /// <summary>
        /// Flash the specified Window (form) for the specified number of times
        /// </summary>
        /// <param name="form">
        /// The Form (Window) to Flash.
        /// </param>
        /// <param name="count">
        /// The number of times to Flash.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool Flash(Form form, uint count)
        {
            if (Win2000OrLater)
            {
                FlashInfo fi = Create_FlashInfo(form.Handle, FlashAll, count, 0);
                return FlashWindowEx(ref fi);
            }

            return false;
        }

        /// <summary>
        /// Start Flashing the specified Window (form)
        /// </summary>
        /// <param name="form">
        /// The Form (Window) to Flash.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool Start(Form form)
        {
            if (Win2000OrLater)
            {
                FlashInfo fi = Create_FlashInfo(form.Handle, FlashAll, uint.MaxValue, 0);
                return FlashWindowEx(ref fi);
            }

            return false;
        }

        /// <summary>
        /// Stop Flashing the specified Window (form).
        /// </summary>
        /// <param name="form">
        /// Current form
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool Stop(Form form)
        {
            if (Win2000OrLater)
            {
                FlashInfo fi = Create_FlashInfo(form.Handle, FlashStop, uint.MaxValue, 0);
                return FlashWindowEx(ref fi);
            }

            return false;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Method to create FlashInfo.
        /// </summary>
        /// <param name="handle">
        /// The handle.
        /// </param>
        /// <param name="flags">
        /// The flags.
        /// </param>
        /// <param name="count">
        /// The count.
        /// </param>
        /// <param name="timeout">
        /// The timeout.
        /// </param>
        /// <returns>
        /// The <see cref="FlashInfo"/>.
        /// </returns>
        private static FlashInfo Create_FlashInfo(IntPtr handle, uint flags, uint count, uint timeout)
        {
            var fi = new FlashInfo();
            fi.CbSize = Convert.ToUInt32(Marshal.SizeOf(fi));
            fi.Hwnd = handle;
            fi.DwFlags = flags;
            fi.FlashesCount = count;
            fi.DwTimeout = timeout;
            return fi;
        }

        /// <summary>
        /// The flash window ex.
        /// </summary>
        /// <param name="flashInfo">
        /// The flashInfo.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool FlashWindowEx(ref FlashInfo flashInfo);

        #endregion

        /// <summary>
        /// The flash info.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct FlashInfo
        {
            /// <summary>
            ///     The size of the structure in bytes.
            /// </summary>
            public uint CbSize;

            /// <summary>
            ///     A Handle to the Window to be Flashed. The window can be either opened or minimized.
            /// </summary>
            public IntPtr Hwnd;

            /// <summary>
            ///     The Flash Status.
            /// </summary>
            public uint DwFlags;

            /// <summary>
            ///     The number of times to Flash the window.
            /// </summary>
            public uint FlashesCount;

            /// <summary>
            ///     The rate at which the Window is to be flashed, in milliseconds. If Zero, the function uses the default cursor blink
            ///     rate.
            /// </summary>
            public uint DwTimeout;
        }
    }
}